// Scenegraph.cpp: implementation of the Scenegraph class.
//
//////////////////////////////////////////////////////////////////////

#include "Scenegraph.h"

/* Project includes */
#include "Defines.h"
#include "Land.h"
#include "Camera.h"
#include "ObjectList.h"
#include "Sky.h"
#include "LensFlare.h"
#include "Waypoint.h"
#include "Movie.h"

static sgVec4 wire_colour = { 0.0f, 1.0f, 0.0f, 1.0f } ;

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Scenegraph::Scenegraph(LoadingInfo *li, Camera *c)
{
	this->camera = c;
	// The first thing to do is create the root node
	this->root = new ssgRoot;
	this->root->setName("ROOT\0");
	this->landTransform = NULL;

	sgZeroCoord(&objectPosition);

	nearestLeaf = NULL;

	movieSelected = -1;

	showObjectTransform = new ssgTransform;
	showObjectTransform -> setTransform(&objectPosition);
	//showObjectTransform -> clrTraversalMaskBits(SSGTRAV_ISECT);
	//showObjectTransform -> clrTraversalMaskBits(SSGTRAV_HOT);

	root->addKid(showObjectTransform);

	objectType = -2;
	objectKind = -2;

	this->info = li;

	time_t t = time ( NULL ) ;
	printf("[%s] Creating buildings list...\n", ctime ( & t ));

	buildingList = new ObjectList(); 
	treeList = new ObjectList();
	textureList = new ObjectList();
	facilityList = new ObjectList();

	this->ck = new ulClock();
	this->sk = NULL;

	old_object_transform = NULL;
	new_object_transform = NULL;

	selectedWaypoint = NULL;
	selectedMovie = NULL;
	movingWaypoint = false;
	movingMovie = false;
}

Scenegraph::~Scenegraph()
{
delete this->root;
}

void Scenegraph::addLand(Land* lnd)
{
time_t t = time ( NULL ) ;
printf("[%s] Adding land...\n", ctime ( & t ));

this->land = lnd;
this->landTransform = land->getTransform();
this->root -> addKid (this->landTransform);

this->x_correction = land->getXCorrection();
this->y_correction = land->getYCorrection();

t = time ( NULL ) ;
printf("[%s] Loading objects...\n", ctime ( & t ));
//loadObjects();
}

void Scenegraph::addWorld()
{

/*Land* north = new Land(info->Ndem_filename,"\0",info);
north->reposition(this->land,NORTH,0);
this->root->addKid(north->getRepositionTransform());

Land* south = new Land(info->Sdem_filename,"\0",info);
float fy = south->reposition(this->land,SOUTH,0);
this->root->addKid(south->getRepositionTransform());

Land* east = new Land(info->Edem_filename,"\0",info);
east->reposition(this->land,EAST,fy);
this->root->addKid(east->getRepositionTransform());

Land* west = new Land(info->Wdem_filename,"\0",info);
west->reposition(this->land,WEST,fy);
this->root->addKid(west->getRepositionTransform());*/
}

void Scenegraph::loadObjects()
{
FILE *f;
char path[2050];
char line[1024];
bool go = FALSE;
int i=0;

ssgTexturePath(TEXTURE_PATH);

// Create object list
this->buildingModelsList = new ulLinkedList();
this->treeModelsList = new ulLinkedList();
this->facilityModelsList = new ulLinkedList();

// Open file
if( (f = fopen(BUILDING_TYPES_FILE_NAME,"r")) != NULL )
	{
	while( fscanf(f,"%s",line) != EOF )
		{
		adjustFileName(line);
		ulMakePath(path,BUILDING_MODELS_PATH,line);
		ssgTransform *t = new ssgTransform();
		ssgEntity *e = ssgLoadAC(path);
		ssgFlatten(e);
		t -> addKid(e);
		ssgStripify(t);
		//e -> clrTraversalMaskBits(SSGTRAV_ISECT);
		//e -> clrTraversalMaskBits(SSGTRAV_HOT);
		buildingModelsList->appendNode(t);
		//t->print(stdout,"",0);
		}
	fclose(f);
	}
else
	{
	printf("Cannot open models file %s\n",BUILDING_TYPES_FILE_NAME);
	}

// Open file
if( (f = fopen(TREE_TYPES_FILE_NAME,"r")) != NULL )
	{
	while( fscanf(f,"%s",line) != EOF )
		{
		adjustFileName(line);
		ulMakePath(path,TREE_MODELS_PATH,line);
		ssgTransform *t = new ssgTransform();
		ssgEntity *e = ssgLoadAC(path);
		ssgFlatten(e);
		t -> addKid(e);
		ssgStripify(t);
		//e -> clrTraversalMaskBits(SSGTRAV_ISECT);
		//e -> clrTraversalMaskBits(SSGTRAV_HOT);
		treeModelsList->appendNode(t);
		//t->print(stdout,"",0);
		}
	fclose(f);
	}
else
	{
	printf("Cannot open models file %s\n",TREE_TYPES_FILE_NAME);
	}

ssgTexturePath(TEXTURE_PATH);
// Open file
if( (f = fopen(FACILITY_TYPES_FILE_NAME,"r")) != NULL )
	{
	while( fscanf(f,"%s",line) != EOF )
		{
		adjustFileName(line);
		ulMakePath(path,FACILITY_MODELS_PATH,line);
		ssgTransform *t = new ssgTransform();
		ssgEntity *e = ssgLoadAC(path);
		ssgFlatten(e);
		t -> addKid(e);
		ssgStripify(t);
		facilityModelsList->appendNode(t);
		//printf("There are %d facility models\n",facilityModelsList->getNumNodes());
		}
	fclose(f);
	}
else
	{
	printf("Cannot open facility file %s\n",FACILITY_TYPES_FILE_NAME);
	}

time_t t = time ( NULL ) ;
printf("[%s] Objects loaded...\n", ctime ( & t ));
}

void Scenegraph::display()
{
if(sk != NULL) 
	{
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	ssgContext *cnt = ssgGetCurrentContext();
	sgCoord campos;
	cnt->getCameraPosition(campos.xyz);
	sk->setCameraPosition(campos);
	ck->update();
	float dt = ck->getDeltaTime();
	//printf("%f\n",dt);
	sk->updateSky(dt);
	//sk->enableFog();
	sk->preDraw();
	}

// if I want to see transparent trees...
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
//glEnable(GL_BLEND);
ssgCullAndDraw(root);

if(sk != NULL)
	{
	//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
	sk->postDraw();
	}
}

void Scenegraph::createStates()
{

}

ssgSimpleState* Scenegraph::createNewState(int type)
{
ssgSimpleState *newState = new ssgSimpleState;

newState = new ssgSimpleState;
newState -> enable( GL_TEXTURE_2D );
newState -> setTexture( info->textures[COUNTRYSIDE_TEXTURES+type] );
newState -> setShadeModel   	( GL_SMOOTH ) ;
newState -> enable		    	( GL_COLOR_MATERIAL ) ;
newState -> enable			    ( GL_CULL_FACE      ) ;

return newState;
}

void Scenegraph::testLOS(sgdLineSegment3* ls, int type, int kind)
{
//printf("Line segment a[%.02f %.02f %.02f] -> b[%.02f %.02f %.02f]\n",ls->a[SG_X],ls->a[SG_Y],ls->a[SG_Z],ls->b[SG_X],ls->b[SG_Y],ls->b[SG_Z]);
//printf("Camera position [%.02f %.02f %.02f - %.02f %.02f %.02f]\n",coord->xyz[SG_X],coord->xyz[SG_Y],coord->xyz[SG_Z],coord->hpr[0],coord->hpr[1],coord->hpr[2]);
bool objectHit = false;
bool objectDestroyed = false;
int objectHitType = -1;
ssgTransform* objectHitTransform = NULL;
ssgTransform* parentObjectHitTransform = NULL;

sgdLine3 line;
sgdLineSegment3 lineseg;

sgdCopyVec3(lineseg.a,ls->b);
sgdCopyVec3(lineseg.b,ls->a);

//printf("%d (%d) %d\n",type, MOVIE_BUTTON_SELECTED, kind);
if( (objectType == MOVIE_BUTTON_SELECTED) && (type != MOVIE_BUTTON_SELECTED) )
	deselectMovie();

//objectType = type;
//objectKind = kind;

sgdLineSegment3ToLine3(&line,lineseg);

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits = 0; 

sgVec3 testVectorLOS;
sgSetVec3(testVectorLOS,(float)line.direction_vector[SG_X],(float)line.direction_vector[SG_Y],(float)line.direction_vector[SG_Z]);

//printf("Line p[%.02f %.02f %.02f] v[%.02f %.02f %.02f]\n",line.point_on_line[SG_X],line.point_on_line[SG_Y],line.point_on_line[SG_Z],line.direction_vector[SG_X],line.direction_vector[SG_Y],line.direction_vector[SG_Z]);

sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4(objectPositionInverseMatrix);

objectPositionInverseMatrix[3][SG_X] = - (float)line.point_on_line[SG_X];
objectPositionInverseMatrix[3][SG_Y] = - (float)line.point_on_line[SG_Y];
objectPositionInverseMatrix[3][SG_Z] = - (float)line.point_on_line[SG_Z];

numberOfHits = ssgLOS ( this->root, testVectorLOS, objectPositionInverseMatrix, &hitResults );
bool alreadyPut = false;

// Read the results
for ( int i = 0 ; i < numberOfHits ; i++ )
	{
	ssgHit *h = &hitResults [ i ] ;
	//printf("H out : %p\n",h);

		for(int p = 0; p < h->getNumPathEntries(); p++)
			{
			//printf("(%d)(%d) NAME = %s\n",i,p,h->getPathEntry(p)->getName());
			if(!objectDestroyed && ulStrEqual(h->getPathEntry(p)->getName(),"OBJECT_TRANSFORM\0"))
				{
				objectHit = true;
				objectHitTransform = (ssgTransform*)h->getPathEntry(p+1);//0
				parentObjectHitTransform = (ssgTransform*)h->getPathEntry(p);//-1
				if(ulStrEqual(h->getPathEntry(p+1)->getName(),"BUILDING_TRANSFORM\0")) 
					{
					objectHitType = OBJECT_TYPE_BUILDING_0;
					//printf("Hit a %s\n",h->getPathEntry(p+1)->getName());
					}
				else if(ulStrEqual(h->getPathEntry(p+1)->getName(),"TREE_TRANSFORM\0")) 
					{
					objectHitType = OBJECT_TYPE_TREE_0;
					//printf("Hit a %s\n",h->getPathEntry(p+1)->getName());
					}
				else if(ulStrEqual(h->getPathEntry(p+1)->getName(),"FACILITY_TRANSFORM\0")) 
					{
					objectHitType = OBJECT_TYPE_FACILITY_0;
					//printf("Hit a %s\n",h->getPathEntry(p+1)->getName());
					}
				}
			}
		//printf("(%d)(%d) NAME = %s\n",i,h->getNumPathEntries(),h->leaf->getName());
	if( (type != BULLDOZER_BUTTON_SELECTED) && (type != WAYPOINTS_BUTTON_SELECTED) && (type != MOVIE_BUTTON_SELECTED) && ulStrEqual(h->leaf->getName(),"TERRAIN_LEAF\0"))
		{
		//printf("Terrain Hit\n");
		//printf("type: %d kind: %d\n",type,kind);
		ssgTransform* tr;
		switch(type)
			{
			case ADD_TREE:
				tr = addObject(OBJECT_TYPE_TREE_0,kind,point[SG_X] + objectPosition.xyz[0],point[SG_Y] + objectPosition.xyz[1],point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
				this->treeList->add(tr,OBJECT_TYPE_TREE_0, kind, point[SG_X] + objectPosition.xyz[0] - x_correction,point[SG_Y] + objectPosition.xyz[1] - y_correction,point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
			break;
			case SET_TEXTURE:
				h->leaf->setState(createNewState(kind));				
				this->textureList->add(NULL,OBJECT_TYPE_TEXTURE_0, kind, point[SG_X] - x_correction,point[SG_Y] - y_correction,point[SG_Z]);
			break;
			case ADD_BUILDING:
				tr = addObject(OBJECT_TYPE_BUILDING_0,kind,point[SG_X] + objectPosition.xyz[0],point[SG_Y] + objectPosition.xyz[1],point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
				this->buildingList->add(tr,OBJECT_TYPE_BUILDING_0, kind, point[SG_X]+ objectPosition.xyz[0] - x_correction,point[SG_Y] + objectPosition.xyz[1] - y_correction,point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
			break;
			case ADD_FACILITY:
				tr = addObject(OBJECT_TYPE_FACILITY_0,kind,point[SG_X] + objectPosition.xyz[0],point[SG_Y] + objectPosition.xyz[1],point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
				this->facilityList->add(tr,OBJECT_TYPE_FACILITY_0, kind, point[SG_X]+ objectPosition.xyz[0] - x_correction,point[SG_Y] + objectPosition.xyz[1] - y_correction,point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
			break;
			default:
			break;
			}
		}
	else if(objectHit && !objectDestroyed)
		{
		if(type == BULLDOZER_BUTTON_SELECTED)
			{
			// remove from the right list
			if(objectHitType == OBJECT_TYPE_BUILDING_0 ) 
				{
				buildingList->remove(objectHitTransform);
				}
			else if(objectHitType == OBJECT_TYPE_TREE_0 ) 
				{
				treeList->remove(objectHitTransform);
				}
			else if(objectHitType == OBJECT_TYPE_FACILITY_0)
				{
				facilityList->remove(objectHitTransform);
				}
			// remove from scenegraph
			//printf("Removing kids from %s...\n",parentObjectHitTransform->getName());
			//parentObjectHitTransform->print(stdout,"",0);
			parentObjectHitTransform->removeAllKids();//((ssgEntity*)objectHitTransform);
			//parentObjectHitTransform->print(stdout,"",0);
			objectDestroyed = true;			
			}
		}
	else if( (type == WAYPOINTS_BUTTON_SELECTED) && !movingWaypoint && !alreadyPut)
		{
		WPCoord* wpc;
		int poz;
		switch(kind)
			{
			case ADD_WAYPOINT:
				this->wp->add(root,point[SG_X],point[SG_Y],point[SG_Z]);
				alreadyPut = true;
			break;
			case DELETE_WAYPOINT:
				this->movingWaypoint = selectWaypoint(h);
				if(movingWaypoint)
					{
					this->wp->remove(root,this->selectedWaypoint);
					this->selectedWaypoint = NULL;
					this->movingWaypoint = false;
					alreadyPut = true;
					objectDestroyed = true;
					}
			break;
			case MOVE_WAYPOINT:
				this->movingWaypoint = selectWaypoint(h);				
			break;
			case INSERT_WAYPOINT:
				//printf("Insert Watpoint\n");
				wpc = selectWaypointLine(h);
				if(wpc != NULL) 
					{
					poz = wp->getPosition(wpc);
					//printf("Waypoint line selected owned by %d\n",wp->getPosition(wpc));
					wp->insert(root,poz-1,poz,point[SG_X],point[SG_Y],point[SG_Z]);
					objectDestroyed = true;
					movingWaypoint = true;
					alreadyPut = true;
					}
			break;
			default:
			break;
			}
		}
	else if( (type == MOVIE_BUTTON_SELECTED) && !movingMovie)
		{
		Frame* fr;
		int poz;

		switch(kind)
			{
			case ADD_MOVIE:
				this->mv->add(root,point[SG_X],point[SG_Y],point[SG_Z]);
				movingMovie = true;
			break;
			case DELETE_MOVIE:
				this->movieSelected = selectMovie(h);
				if(movieSelected != -1)
					{
					this->mv->remove(this->selectedMovie);
					this->selectedMovie = NULL;
					this->movieSelected = -1;
					movingMovie = true;
					objectDestroyed = true;
					}
			break;
			case MOVE_MOVIE:
				this->movieSelected = selectMovie(h);
				//movingMovie = true;
			break;
			case INSERT_MOVIE:
				printf("Insert Movie\n");
				fr = selectMovieLine(h);
				findNearestMovieLine(ls);
				if(fr != NULL) 
					{
					poz = mv->getPosition(fr);
					printf("Frame line selected owned by %d\n",mv->getPosition(fr));
					mv->insert(root,poz-1,poz,movie_line_point[SG_X],movie_line_point[SG_Y],movie_line_point[SG_Z]);
					objectDestroyed = true;
					movingMovie = true;
					}
			break;
			default:
			break;
			}
		}
	}
movingMovie = false;
alreadyPut = false;
}

Frame* Scenegraph::selectMovieLine(ssgHit *h)
{
Frame *fr = NULL;
for(int p = 0; p < h->getNumPathEntries(); p++)
	{
	if(ulStrEqual(h->getPathEntry(p)->getName(),"MOVIE_LINE_TRANSFORM\0"))
		{
		printf("Gotcha!\n");
		fr = mv->get((ssgTransform*)h->getPathEntry(p),TRACK);
		return fr;
		}
	}
return NULL;
}

WPCoord* Scenegraph::selectWaypointLine(ssgHit *h)
{
WPCoord *wpc = NULL;
for(int p = 0; p < h->getNumPathEntries(); p++)
	{
	if(ulStrEqual(h->getPathEntry(p)->getName(),"LINE_TRANSFORM\0"))
		{
		printf("Gotcha WP!\n");
		wpc = wp->get((ssgTransform*)h->getPathEntry(p),LINE);
		return wpc;
		}
	}
return NULL;
}

bool Scenegraph::selectWaypoint(ssgHit *h)
{
for(int p = 0; p < h->getNumPathEntries(); p++)
	{
	if(ulStrEqual(h->getPathEntry(p)->getName(),"WAYPOINT_TRANSFORM\0"))
		{
		WPCoord* wpc = wp->get((ssgTransform*)h->getPathEntry(p),ARROW);
		selectedWaypoint = wpc;
		return true;
		}
	}
return false;
}

int Scenegraph::selectMovie(ssgHit *h)
{
bool go = true;
int pos = -1; 
for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
	{
	if(ulStrEqual(h->getPathEntry(p)->getName(),"MOVIE_TRANSFORM\0"))
		{
		Frame* fr = mv->get((ssgTransform*)h->getPathEntry(p));
		pos = mv->getPosition(fr);
		deselectMovie();
		selectedMovie = fr;
		//printf("Movie selected %p (%d)\n",selectedMovie,pos);
		ssgSelector *new_s = (ssgSelector*)selectedMovie->cameraTransform->getKid(0);
		new_s -> selectStep(MOVIE_SELECTED);
		go = false;
		return pos;
		}
	}
return pos;
}

void Scenegraph::stopAction()
{
if(movingWaypoint)
	{
	movingWaypoint = false;
	selectedWaypoint = NULL;
	}
}

void Scenegraph::deselectMovie()
{
if(selectedMovie != NULL) 
	{
	ssgSelector *old_s = (ssgSelector*)selectedMovie->cameraTransform->getKid(0);
	old_s -> selectStep(MOVIE_NORMAL);
	}
}

void Scenegraph::showObject(sgdLineSegment3* ls, int type, int kind)
{
//printf("Line segment a[%.02f %.02f %.02f] -> b[%.02f %.02f %.02f] (%f)\n",ls->a[SG_X],ls->a[SG_Y],ls->a[SG_Z],ls->b[SG_X],ls->b[SG_Y],ls->b[SG_Z],sgdDistanceVec3(ls->a,ls->b));

bool change = false;

if(objectType != type)
	{
	objectType = type;
	change = true;
	}
if(objectKind != kind)
	{
	objectKind = kind;
	change = true;
	}

sgdLine3 line;
sgdLineSegment3 lineseg;

sgdCopyVec3(lineseg.a,ls->b);
sgdCopyVec3(lineseg.b,ls->a);

sgdLineSegment3ToLine3(&line,lineseg);

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits = 0; 

sgVec3 testVectorLOS;
sgSetVec3(testVectorLOS,(float)line.direction_vector[SG_X],(float)line.direction_vector[SG_Y],(float)line.direction_vector[SG_Z]);

sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4(objectPositionInverseMatrix);

objectPositionInverseMatrix[3][SG_X] = - (float)line.point_on_line[SG_X];
objectPositionInverseMatrix[3][SG_Y] = - (float)line.point_on_line[SG_Y];
objectPositionInverseMatrix[3][SG_Z] = - (float)line.point_on_line[SG_Z];


numberOfHits = ssgLOS ( this->root, testVectorLOS, objectPositionInverseMatrix, &hitResults );


// Read the results
for ( int i = 0 ; i < numberOfHits ; i++ )
	{
	ssgHit *h = &hitResults [ i ] ;
	bool terrain = false;
	bool go = true;
	for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
		{
		if(ulStrEqual(h->getPathEntry(p)->getName(),"LAND_TRANSFORM\0"))
			terrain = true;
		else if(ulStrEqual(h->getPathEntry(p)->getName(),"WAYPOINT_TRACK\0"))
			{
			//printf("LINE OWNED BY: %d\n",wp->getPosition(wp->get((ssgTransform*)h->getPathEntry(p+1),LINE)));
			terrain = false;
			go = false;
			}
		}
	if(terrain && ulStrEqual(h->leaf->getName(),"TERRAIN_LEAF\0"))
		{
		//sgCopyVec3(point,nearest_point);
		if (movingWaypoint)
			{
			this->wp->reposition(root,selectedWaypoint,point[SG_X],point[SG_Y],point[SG_Z]);
			}
		else 
			{
			if( change ) // new object selected
				selectObject(objectType,objectKind,point[SG_X],point[SG_Y],point[SG_Z]);
			else // just reposition old object
				repositionObject(point[SG_X],point[SG_Y],point[SG_Z]);
			}
		}

	}

}

void Scenegraph::selectObject(int type, int kind, float x, float y, float z)
{
//printf("type : %d - kind : %d\n",type,kind);
if(this->showObjectTransform != NULL) 
	{
	this->showObjectTransform->removeAllKids();//(old_object_transform);
	old_object_transform = NULL;
	}

// What kind of list is it???
switch(type)
	{
	case ADD_BUILDING:
		//printf("Add tree\n");
		new_object_transform = (ssgTransform*)((ssgTransform*)buildingModelsList->getNodeData(kind))->clone(SSG_CLONE_RECURSIVE|SSG_CLONE_GEOMETRY);
		//new_object_transform->print(stdout," ",0);
	break;
	case ADD_TREE:
		//printf("Add tree\n");
		new_object_transform = (ssgTransform*)((ssgTransform*)treeModelsList->getNodeData(kind))->clone(SSG_CLONE_RECURSIVE|SSG_CLONE_GEOMETRY);
		//new_object_transform->print(stdout," ",0);
	break;
	case ADD_FACILITY:
		//printf("Add facility\n");
		new_object_transform = (ssgTransform*)((ssgTransform*)facilityModelsList->getNodeData(kind))->clone(SSG_CLONE_RECURSIVE|SSG_CLONE_GEOMETRY);
		//new_object_transform->print(stdout," ",0);
	break;
	default:
	break;
	}

if( (new_object_transform != NULL) && ((type == OBJECT_TYPE_TREE_0) || (type == OBJECT_TYPE_BUILDING_0) || (type == OBJECT_TYPE_FACILITY_0)) )
	{
	sgCoord objectCoord;
	sgSetCoord(&objectCoord,x + objectPosition.xyz[0],y + objectPosition.xyz[1],z + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
	this->showObjectTransform -> setTransform(&objectCoord);
	this->showObjectTransform -> addKid(new_object_transform);
	}
old_object_transform = new_object_transform;
}

void Scenegraph::repositionObject(float x, float y, float z)
{
if(this->showObjectTransform != NULL)
	{
	sgCoord objectCoord;

	sgSetCoord(&objectCoord,x + objectPosition.xyz[0],y + objectPosition.xyz[1],z + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);

	this->showObjectTransform -> setTransform(&objectCoord);
	}
}

ssgEntity* Scenegraph::loadTree()
{
return ssgLoadAC("./pineTreeNear.ac");
}

ssgTransform* Scenegraph::addObject(int type, int kind, float x, float y, float z, float h, float p, float r)
{
ssgTransform *t;
// What kind of list is it???
switch(type)
	{
	case ADD_BUILDING:
		t = (ssgTransform*)buildingModelsList->getNodeData(kind);

	break;
	case ADD_TREE:
		t = (ssgTransform*)treeModelsList->getNodeData(kind);

	break;
	case ADD_FACILITY:
		t = (ssgTransform*)facilityModelsList->getNodeData(kind);
	break;
	default:
	break;
	}

if(t != NULL)
	{
	ssgTransform *new_object = new ssgTransform;
	ssgTransform *new_object2 = new ssgTransform;
	sgCoord objectCoord;

	sgSetCoord(&objectCoord,x,y,z,h,p,r);

	new_object -> setTransform(&objectCoord);
	new_object -> addKid(t);
	
	if(type == ADD_BUILDING)
		new_object -> setName("BUILDING_TRANSFORM\0");
	else if(type == ADD_TREE)
		new_object -> setName("TREE_TRANSFORM\0");
	else if(type == ADD_FACILITY)
		new_object -> setName("FACILITY_TRANSFORM\0");

	new_object -> clrTraversalMaskBits(SSGTRAV_ISECT);
	new_object -> clrTraversalMaskBits(SSGTRAV_HOT);
	new_object2 -> addKid(new_object);
	new_object2 ->setName("OBJECT_TRANSFORM\0");
	this->root->addKid(new_object2);
	return new_object;
	}
return NULL;
}

void Scenegraph::addTree(float x, float y, float z)
{
if(this->pineTreeModel != NULL)
	{
	ssgTransform *new_pineTree = new ssgTransform;
	sgCoord pineCoord;

	sgSetCoord(&pineCoord,x + objectPosition.xyz[0],y + objectPosition.xyz[1],z + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);


	new_pineTree -> setTransform(&pineCoord);
	new_pineTree -> addKid(this->pineTreeModel);
	new_pineTree -> clrTraversalMaskBits(SSGTRAV_ISECT);
	new_pineTree -> clrTraversalMaskBits(SSGTRAV_HOT);
	this->root->addKid(new_pineTree);
	}
}

ssgEntity* Scenegraph::loadBuilding()
{
return ssgLoadAC("./house.ac");
}

void Scenegraph::addBuilding(float x, float y, float z)
{
if(this->houseModel != NULL)
	{
	ssgTransform *new_house = new ssgTransform;
	sgCoord houseCoord;

	sgSetCoord(&houseCoord,x + objectPosition.xyz[0],y + objectPosition.xyz[1],z + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);


	new_house -> setTransform(&houseCoord);
	new_house -> addKid(this->houseModel);
	new_house -> clrTraversalMaskBits(SSGTRAV_ISECT);
	new_house -> clrTraversalMaskBits(SSGTRAV_HOT);
	this->root->addKid(new_house);
	}
}

ObjectList* Scenegraph::getList(int type)
{
switch(type)
	{
	case TREE_LIST:
		return treeList;
	break;
	case BUILDING_LIST:
		return buildingList;
	break;
	case TEXTURE_LIST:
		return textureList;
	break;
	case FACILITY_LIST:
		return facilityList;
	break;
	default:
		return NULL;
	break;
	}
}

void Scenegraph::load()
{
int n;
//int i;

ssgTransform *t;

n = treeList->getSize();

for(int i = 0; i < n; i++)
	{
	ObjectSlot *os = treeList->get(i);
	t = this->addObject(os->type,os->kind,os->x + x_correction,os->y + y_correction,os->z,os->h,os->p,os->r);
	treeList->set(t,i);
	}

n = buildingList->getSize();
		
for(int jl = 0; jl < n; jl++)
	{
	ObjectSlot *os = buildingList->get(jl);
	t = this->addObject(os->type,os->kind,os->x + x_correction,os->y + y_correction,os->z,os->h,os->p,os->r);
	buildingList->set(t,jl);
	}

n = textureList->getSize();

for(int k = 0; k < n; k++)
	{
	ObjectSlot *os = textureList->get(k);
	this->addTexture(os->kind,os->x + x_correction,os->y + y_correction,os->z);
	}

n = facilityList->getSize();
//printf("Loading facilities\n");
for(int r = 0; r < n; r++)
	{
	ObjectSlot *os = facilityList->get(r);
	t = this->addObject(os->type,os->kind,os->x + x_correction,os->y + y_correction,os->z,os->h,os->p,os->r);
	facilityList->set(t,r);
	}

//printf("Facility Loaded\n");

this->cameraStartPosition.xyz[0] += x_correction;
this->cameraStartPosition.xyz[1] += y_correction;
this->camera->setCameraPosition(this->cameraStartPosition);
}

void Scenegraph::addTexture(int kind, float x,float y,float z)
{
sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4 ( objectPositionInverseMatrix ) ;

objectPositionInverseMatrix[3][SG_X] =  - x;
objectPositionInverseMatrix[3][SG_Y] =  - y;
objectPositionInverseMatrix[3][SG_Z] =  0.0f;

// Test vector for HOT: vector is perpendicular to the xy plane
sgVec3 testVectorHOT;

testVectorHOT[SG_X] = 0.0f;
testVectorHOT[SG_Y] = 0.0f;
testVectorHOT[SG_Z] = 100000.0f;

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits;
	
// Test database for HOT...
numberOfHits = ssgHOT ( this->root, testVectorHOT, objectPositionInverseMatrix, &hitResults );
			
// Read the results
for ( int k = 0 ; k < numberOfHits ; k++ )
	{
	ssgHit *h = &hitResults [ k ] ;
	h->leaf->setState(loadTextureState(kind));
	for(int c = 0; c < 4; c++)
		{
		float *col = h->leaf->getColour(c);
		sgSetVec4(col,LAND_ICE);
		}
	}
}

ssgSimpleState* Scenegraph::loadTextureState(int kind)
{
// textures have already been loaded in the main thread
ssgSimpleState *newState = new ssgSimpleState;

GLint textnum;
doCritical(textnum = info->textures[COUNTRYSIDE_TEXTURES+kind],info->cs);

newState = new ssgSimpleState;
newState -> enable				( GL_TEXTURE_2D );
newState -> setTexture			( textnum );
newState -> setShadeModel   	( GL_SMOOTH ) ;
newState -> enable		    	( GL_COLOR_MATERIAL ) ;
newState -> enable			    ( GL_CULL_FACE      ) ;
//newState -> setMaterial			( GL_AMBIENT, LAND_WHITE);

return newState;
}

void Scenegraph::addSky()
{
this->sk = new Sky();
this->skyTransform = sk->getTransform();
this->sk->enableFog();
this->root->addKid(skyTransform);
this->lf = new LensFlare(this->skyTransform);
}

void Scenegraph::addWaypoints(char filename[])
{
this->wp = new Waypoint(filename,this->land->getXCorrection(),this->land->getYCorrection());
this->wp->create(this->root);
}

void Scenegraph::hideWaypoints()
{
this->wp->hideWaypoints();
}

void Scenegraph::addMovie(char filename[])
{
this->mv = new Movie(filename,this->land->getXCorrection(),this->land->getYCorrection());
this->mv->create(this->root);
}

void Scenegraph::setWireframe(int s)
{
this->land->setWireframe(s);
}

void Scenegraph::updateObjectPosition(int what, float howMuch)
{
switch(what)
	{
	case X_POSITION:
		objectPosition.xyz[0] += howMuch;
		break;
	case Y_POSITION:
		objectPosition.xyz[1] += howMuch;
		break;
	case Z_POSITION:
		objectPosition.xyz[2] += howMuch;
		break;
	case H_POSITION:
		objectPosition.hpr[0] += howMuch;
		break;
	case P_POSITION:
		objectPosition.hpr[1] += howMuch;
		break;
	case R_POSITION:
		objectPosition.hpr[2] += howMuch;
		break;
	default:
	break;
	}
sgCoord objectCoord;
sgSetCoord(&objectCoord,point[SG_X] + objectPosition.xyz[0],point[SG_Y] + objectPosition.xyz[1],point[SG_Z] + objectPosition.xyz[2],objectPosition.hpr[0],objectPosition.hpr[1],objectPosition.hpr[2]);
this->showObjectTransform -> setTransform(&objectCoord);
}

void Scenegraph::printTr()
{
sgMat4 m;
sgCoord c;
showObjectTransform->getTransform(m);
sgSetCoord(&c,m);
printf("%f %f %f %f %f %f\n",c.xyz[0],c.xyz[1],c.xyz[2],c.hpr[0],c.hpr[1],c.hpr[2]);
}

Waypoint* Scenegraph::getWaypoints()
{
return this->wp;
}

float Scenegraph::findNearestTerrainLeaf(sgdLineSegment3* ls)
{
float minDistance = 100000000.0f;
int nl = -1;

sgdLine3 line;
sgdLineSegment3 lineseg;

sgdCopyVec3(lineseg.a,ls->a);
sgdCopyVec3(lineseg.b,ls->b);

sgdLineSegment3ToLine3(&line,lineseg);

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits = 0; 

sgVec3 testVectorLOS;
sgSetVec3(testVectorLOS,(float)line.direction_vector[SG_X],(float)line.direction_vector[SG_Y],(float)line.direction_vector[SG_Z]);

sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4(objectPositionInverseMatrix);

objectPositionInverseMatrix[3][SG_X] = - (float)line.point_on_line[SG_X];
objectPositionInverseMatrix[3][SG_Y] = - (float)line.point_on_line[SG_Y];
objectPositionInverseMatrix[3][SG_Z] = - (float)line.point_on_line[SG_Z];

numberOfHits = ssgLOS ( this->root, testVectorLOS, objectPositionInverseMatrix, &hitResults );

int tr = -1;

// Read the results
for ( int i = 0 ; i < numberOfHits ; i++ )
	{
	ssgHit *h = &hitResults [ i ] ;
	bool go = true;
	for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
		{
		go = true;
		if(ulStrEqual(h->getPathEntry(p)->getName(),"LAND_TRANSFORM\0") && ulStrEqual(h->leaf->getName(),"TERRAIN_LEAF\0"))
			{
			float *va,*vb,*vc;
			short a,b,c;
			int t;

			t = h->triangle;

			h->leaf->getTriangle(t,&a,&b,&c);

			va = h->leaf->getVertex(a);
			vb = h->leaf->getVertex(b);
			vc = h->leaf->getVertex(c);

			sgMat4 transform;
			sgCopyMat4(transform,h->matrix);
			sgInvertMat4(objectPositionInverseMatrix);
			sgMat4 cltr;
			sgMultMat4(cltr,transform,objectPositionInverseMatrix);

			float vat[3],vbt[3],vct[3];
			sgXformPnt3(vat,va,cltr);
			sgXformPnt3(vbt,vb,cltr);
			sgXformPnt3(vct,vc,cltr);

			sgVec4 plane;
			sgMakePlane(plane,vat,vbt,vct);

			sgVec3 v1,v2;
			sgSetVec3(v1,(float)lineseg.a[SG_X],(float)lineseg.a[SG_Y],(float)lineseg.a[SG_Z]);
			sgSetVec3(v2,(float)lineseg.b[SG_X],(float)lineseg.b[SG_Y],(float)lineseg.b[SG_Z]);
			sgVec3 current_point;
			float isec = sgIsectLinesegPlane(current_point,v1,v2,plane);
			if(isec >= 1.0f)
				{
				t = h->triangle;

				h->leaf->getTriangle(t,&c,&b,&c);

				va = h->leaf->getVertex(a);
				vb = h->leaf->getVertex(b);
				vc = h->leaf->getVertex(c);

				sgMat4 transform;
				sgCopyMat4(transform,h->matrix);
				sgInvertMat4(objectPositionInverseMatrix);
				sgMat4 cltr;
				sgMultMat4(cltr,transform,objectPositionInverseMatrix);

				float vat[3],vbt[3],vct[3];
				sgXformPnt3(vat,va,cltr);
				sgXformPnt3(vbt,vb,cltr);
				sgXformPnt3(vct,vc,cltr);

				sgVec4 plane;
				sgMakePlane(plane,vat,vbt,vct);

				sgVec3 v1,v2;
				sgSetVec3(v1,(float)lineseg.a[SG_X],(float)lineseg.a[SG_Y],(float)lineseg.a[SG_Z]);
				sgSetVec3(v2,(float)lineseg.b[SG_X],(float)lineseg.b[SG_Y],(float)lineseg.b[SG_Z]);
				isec = sgIsectLinesegPlane(current_point,v1,v2,plane);
				}

			float dst = sgDistanceVec3(camera->getCameraPosition()->xyz,current_point);
			if(dst < minDistance)
				{
				nearestLeaf = h->leaf;
				minDistance = dst;
				sgCopyVec3(nearest_point,current_point);
				nl = i;
				tr = t;
				}
			go = false;
			}
		}
	}
sgCopyVec3(point,nearest_point);
return minDistance;
}


float Scenegraph::findNearestMovieLine(sgdLineSegment3* ls)
{
float minDistance = 100000000.0f;
int nl = -1;

sgdLine3 line;
sgdLineSegment3 lineseg;

sgdCopyVec3(lineseg.a,ls->a);
sgdCopyVec3(lineseg.b,ls->b);

sgdLineSegment3ToLine3(&line,lineseg);

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits = 0; 

sgVec3 testVectorLOS;
sgSetVec3(testVectorLOS,(float)line.direction_vector[SG_X],(float)line.direction_vector[SG_Y],(float)line.direction_vector[SG_Z]);

sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4(objectPositionInverseMatrix);

objectPositionInverseMatrix[3][SG_X] = - (float)line.point_on_line[SG_X];
objectPositionInverseMatrix[3][SG_Y] = - (float)line.point_on_line[SG_Y];
objectPositionInverseMatrix[3][SG_Z] = - (float)line.point_on_line[SG_Z];

numberOfHits = ssgLOS ( this->root, testVectorLOS, objectPositionInverseMatrix, &hitResults );
	
int tr = -1;

// Read the results
for ( int i = 0 ; i < numberOfHits ; i++ )
	{
	ssgHit *h = &hitResults [ i ] ;
	bool go = true;
	for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
		{
		go = true;
		if(ulStrEqual(h->getPathEntry(p)->getName(),"MOVIE_LINE_TRANSFORM\0") && ulStrEqual(h->leaf->getName(),"MOVIE_LINE\0"))
			{
			float *va,*vb,*vc;
			short a,b,c;
			int t;

			t = h->triangle;

			h->leaf->getTriangle(t,&a,&b,&c);

			va = h->leaf->getVertex(a);
			vb = h->leaf->getVertex(b);
			vc = h->leaf->getVertex(c);

			sgMat4 transform;
			sgCopyMat4(transform,h->matrix);
			sgInvertMat4(objectPositionInverseMatrix);
			sgMat4 cltr;
			sgMultMat4(cltr,transform,objectPositionInverseMatrix);

			float vat[3],vbt[3],vct[3];
			sgXformPnt3(vat,va,cltr);
			sgXformPnt3(vbt,vb,cltr);
			sgXformPnt3(vct,vc,cltr);

			sgVec4 plane;
			sgMakePlane(plane,vat,vbt,vct);

			sgVec3 v1,v2;
			sgSetVec3(v1,(float)lineseg.a[SG_X],(float)lineseg.a[SG_Y],(float)lineseg.a[SG_Z]);
			sgSetVec3(v2,(float)lineseg.b[SG_X],(float)lineseg.b[SG_Y],(float)lineseg.b[SG_Z]);
			sgVec3 current_point;
			float isec = sgIsectLinesegPlane(current_point,v1,v2,plane);
			if(isec >= 1.0f)
				{
				t = h->triangle;

				h->leaf->getTriangle(t,&c,&b,&c);

				va = h->leaf->getVertex(a);
				vb = h->leaf->getVertex(b);
				vc = h->leaf->getVertex(c);

				sgMat4 transform;
				sgCopyMat4(transform,h->matrix);
				sgInvertMat4(objectPositionInverseMatrix);
				sgMat4 cltr;
				sgMultMat4(cltr,transform,objectPositionInverseMatrix);

				float vat[3],vbt[3],vct[3];
				sgXformPnt3(vat,va,cltr);
				sgXformPnt3(vbt,vb,cltr);
				sgXformPnt3(vct,vc,cltr);

				sgVec4 plane;
				sgMakePlane(plane,vat,vbt,vct);

				sgVec3 v1,v2;
				sgSetVec3(v1,(float)lineseg.a[SG_X],(float)lineseg.a[SG_Y],(float)lineseg.a[SG_Z]);
				sgSetVec3(v2,(float)lineseg.b[SG_X],(float)lineseg.b[SG_Y],(float)lineseg.b[SG_Z]);
				isec = sgIsectLinesegPlane(current_point,v1,v2,plane);
				}

			float dst = sgDistanceVec3(camera->getCameraPosition()->xyz,current_point);
			if(dst < minDistance)
				{
				nearestLeaf = h->leaf;
				minDistance = dst;
				sgCopyVec3(nearest_point,current_point);
				nl = i;
				tr = t;
				}
			go = false;
			}
		}
	}
sgCopyVec3(movie_line_point,nearest_point);
return minDistance;
}


Movie* Scenegraph::getMovie()
{
return mv;
}

float Scenegraph::getHOT(float x, float y)
{
sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4 ( objectPositionInverseMatrix ) ;

objectPositionInverseMatrix[3][SG_X] =  - (x);
objectPositionInverseMatrix[3][SG_Y] =  - (y);
objectPositionInverseMatrix[3][SG_Z] =  0.0f;

// Test vector for HOT: vector is perpendicular to the xy plane
sgVec3 testVectorHOT;

testVectorHOT[SG_X] = 0.0f;
testVectorHOT[SG_Y] = 0.0f;
testVectorHOT[SG_Z] = 100000.0f;

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits;
float   hot = -9999.0f;

// Test database for HOT...
numberOfHits = ssgHOT ( root, testVectorHOT, objectPositionInverseMatrix, &hitResults );
			
// Read the results
for ( int k = 0 ; k < numberOfHits ; k++ )
	{
	ssgHit *h = &hitResults [ k ] ;
	
	float hgt = - h->plane[3] / h->plane[2] ;
	if ( hgt >= hot )
		{
		bool terrain = false;
		bool go = true;
		for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
			{
			//printf("%s\n",h->getPathEntry(p)->getName());
			if(ulStrEqual(h->getPathEntry(p)->getName(),"LAND_TRANSFORM\0"))
				{
				terrain = true;
				hot = hgt ;
				}
			else if(ulStrEqual(h->getPathEntry(p)->getName(),"WAYPOINT_TRACK\0"))
				{
				terrain = false;
				go = false;
				}
			}
		}
	}

return hot;
}

float* Scenegraph::getPointerPosition()
{
return this->point;
}

void Scenegraph::switchToEditingView()
{
mv->end();
printf("Switching to editing view!\n");
if(selectedMovie != NULL)
	{
	sgCoord current_movie;
	sgCopyCoord(&current_movie,camera->getMoviePosition());
	selectedMovie->e = current_movie.xyz[SG_X] - land->getXCorrection(), 
	selectedMovie->n = current_movie.xyz[SG_Y] - land->getYCorrection(), 
	selectedMovie->z = getHeigth(current_movie.xyz[SG_X],current_movie.xyz[SG_Y]);
	selectedMovie->a = current_movie.xyz[SG_Z] - selectedMovie->z;
	selectedMovie->az = selectedMovie->a + selectedMovie->z;
	selectedMovie->h = current_movie.hpr[0];
	selectedMovie->p = current_movie.hpr[1];
	selectedMovie->r = current_movie.hpr[2];
	selectedMovie->cameraTransform->setTraversalMaskBits(SSGTRAV_CULL);
	mv->reposition(root,selectedMovie,current_movie.xyz[SG_X],current_movie.xyz[SG_Y],selectedMovie->z);
	}
else 
	{
	printf("No Movie for Returning...\n");
	}

}

void Scenegraph::switchToCameraRepositioningView()
{
if(selectedMovie != NULL)
	{
	sgCoord current_movie;
	sgSetCoord(&current_movie,selectedMovie->e + land->getXCorrection(), selectedMovie->n + land->getYCorrection(), selectedMovie->a + selectedMovie->z, selectedMovie->h, selectedMovie->p, selectedMovie->r);
	//printf("Selected Movie Position: %.02f %.02f %.02f %.02f %.02f %.02f\n",current_movie.xyz[SG_X],current_movie.xyz[SG_Y],current_movie.xyz[SG_Z],current_movie.hpr[0],current_movie.hpr[1],current_movie.hpr[2]);
	camera->setMoviePosition(current_movie);
	selectedMovie->cameraTransform->clrTraversalMaskBits(SSGTRAV_CULL);
	}
else 
	{
	printf("No Movie to Edit...\n");
	}
}

void Scenegraph::switchToMovieView()
{
this->mv->start();
}

float Scenegraph::getHeigth(float x, float y)
{
sgMat4 objectPositionInverseMatrix;
sgMakeIdentMat4 ( objectPositionInverseMatrix ) ;

objectPositionInverseMatrix[3][SG_X] =  - (x);
objectPositionInverseMatrix[3][SG_Y] =  - (y);
objectPositionInverseMatrix[3][SG_Z] =  0.0f;

// Test vector for HOT: vector is perpendicular to the xy plane
sgVec3 testVectorHOT;

testVectorHOT[SG_X] = 0.0f;
testVectorHOT[SG_Y] = 0.0f;
testVectorHOT[SG_Z] = 100000.0f;

// ssgHit structure, it will contain the colliding triangles
ssgHit *hitResults;
int     numberOfHits;
float   hot = -9999.0f;

// Test database for HOT...
numberOfHits = ssgHOT ( root, testVectorHOT, objectPositionInverseMatrix, &hitResults );
			
// Read the results
for ( int k = 0 ; k < numberOfHits ; k++ )
	{
	ssgHit *h = &hitResults [ k ] ;
	
	float hgt = - h->plane[3] / h->plane[2] ;
	if ( hgt >= hot )
		{
		bool terrain = false;
		bool go = true;
		for(int p = 0; (p < h->getNumPathEntries()) && go; p++)
			{
			//printf("%s\n",h->getPathEntry(p)->getName());
			if(ulStrEqual(h->getPathEntry(p)->getName(),"LAND_TRANSFORM\0"))
				{
				terrain = true;
				hot = hgt ;
				}
			else if(ulStrEqual(h->getPathEntry(p)->getName(),"WAYPOINT_TRACK\0"))
				{
				terrain = false;
				go = false;
				}
			}
		}
	}

return hot;
}

void Scenegraph::setCameraStartPosition(float x, float y, float z, float h, float p, float r)
{
sgSetCoord(&cameraStartPosition,x,y,z,h,p,r);
}

static int wire_draw ( ssgEntity* e )
{
  if ( e -> isAKindOf ( ssgTypeLeaf() ) )
  {
    ssgLeaf* leaf = (ssgLeaf*) e ;
    leaf -> drawHighlight ( wire_colour ) ;
  }
  return 1 ;
}


static void wire_update ( ssgEntity *e, int flag )
{
  if ( e -> isAKindOf ( ssgTypeBranch() ) )
  {
    ssgBranch *br = (ssgBranch *) e ;
    
    for ( int i = 0 ; i < br -> getNumKids () ; i++ )
      wire_update ( br -> getKid ( i ), flag ) ;
  }
  else if ( e -> isAKindOf ( ssgTypeLeaf() ) )
  {
    ssgLeaf* leaf = (ssgLeaf *) e ;
    leaf -> setCallback ( SSG_CALLBACK_POSTDRAW, flag? wire_draw: NULL ) ;
  }
}
